package com.github.lh.controller;

import com.github.lh.common.ReturnCode;
import com.github.lh.common.ReturnModel;
import com.github.lh.service.BaseService;
import com.querydsl.core.types.Predicate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;

import static com.github.lh.common.BindingResultErrorsExtractor.extractErrorsReturn;
import static com.github.lh.common.ReturnModel.ok;

/**
 * @author <a href="mailto: 393803588@qq.com">刘涵(Hanl)</a>
 * By 2017/12/1
 */
@RestController
public abstract class BaseController<T, ID extends Serializable> {

    /**
     * universal getById method
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
    public ReturnModel<T> getById(@PathVariable(name = "id") ID id) {
        return ok(getService().getOne(id));
    }

    /**
     * universal query method
     *
     * @param predicate
     * @return
     */
    @RequestMapping(value = "/query", method = RequestMethod.GET)
    public ReturnModel<Iterable<T>> query(@QuerydslPredicate Predicate predicate) {
        return ok(getService().findAll(predicate));
    }

    /**
     * universal page query method
     *
     * @param predicate
     * @param pageable
     * @return
     */
    @RequestMapping(value = "/pageQuery", method = RequestMethod.GET)
    public ReturnModel<Page<T>> pageQuery(@QuerydslPredicate Predicate predicate,
                                          @RequestParam Pageable pageable) {
        return ok(getService().findAll(predicate, pageable));
    }

    /**
     * universal save method
     *
     * @param s
     * @param result
     * @param <S>
     * @return
     */
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public <S extends T> ReturnModel<?> save(@Validated S s,
                                             BindingResult result) {
        if (result.hasErrors()) {
            return ok(ReturnCode.BAD_REQUEST, extractErrorsReturn(result));
        }
        return ok(getService().save(s));
    }

    /**
     * universal update method
     *
     * @param s
     * @param result
     * @param <S>
     * @return
     */
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public <S extends T> ReturnModel<?> update(@Validated S s,
                                               BindingResult result) {
        if (result.hasErrors()) {
            return ok(ReturnCode.BAD_REQUEST, extractErrorsReturn(result));
        }
        return ok(getService().save(s));
    }

    /**
     * universal delete method
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
    public ReturnModel delete(@PathVariable(name = "id") ID id) {
        getService().delete(id);
        return ok();
    }

    abstract BaseService<T, ID> getService();
}
